import base64
import os
import json
import time
import urllib.parse

import requests
from typing import Optional
from fastapi import APIRouter, Form, File, UploadFile, Header, HTTPException
from apscheduler.schedulers.asyncio import AsyncIOScheduler  # 异步调度器
from qiniu import Auth, put_data

from app.page.page_user import page_user
from models.m import User, AuthorVerification, AuthorVerificationStatus
from tool.jwt_utils import get_current_user
# 创建异步Redis连接
import redis.asyncio as redis_async

from typing import List, Dict

from apscheduler.schedulers.background import BackgroundScheduler
from fastapi import APIRouter
from starlette.websockets import WebSocket
from tortoise.contrib.aiohttp import register_tortoise




list_rz_wedSockert = APIRouter()



# 假设以下模型和工具已定义
redis_conn = redis_async.Redis(host='127.0.0.1', port=6379, db=0)

# 百度OCR配置
API_KEY = "LUEeCmxq5nifS0yxzBR9m5J2"
SECRET_KEY = "2TnBiY0o0ZzGRBUzvmig6liXaGsv66xg"

# 七牛云配置
QINIU_ACCESS_KEY = 'IPzQQFeLOA4fPDWzUTQQX7eJ4OcAfyzDyR3A3HN6'
QINIU_SECRET_KEY = 'hi1t3IWhYxp5H-SI7sJnFLHR9x_oUt8mFeYtuz6z'
QINIU_BUCKET = '653ef'
QINIU_DOMAIN = 'http://t4y377zln.hb-bkt.clouddn.com'

# 路由和调度器初始化
scheduler = AsyncIOScheduler()


# ------------------------------
# 1. 百度OCR识别工具 (修改为支持URL)
# ------------------------------
def get_access_token():
    """获取百度API的access_token"""
    url = "https://aip.baidubce.com/oauth/2.0/token"
    params = {
        "grant_type": "client_credentials",
        "client_id": API_KEY,
        "client_secret": SECRET_KEY
    }
    try:
        response = requests.post(url, params=params)
        result = response.json()
        return result.get("access_token")
    except Exception as e:
        print(f"获取token失败: {str(e)}")
        return None


def ocr_id_card(img_url):
    """从URL识别身份证正面信息"""
    # 1. 下载图片
    try:
        resp = requests.get(img_url, timeout=10)
        resp.raise_for_status()
        img_data = resp.content
    except Exception as e:
        raise Exception(f"下载图片失败: {str(e)}")

    # 2. 检查大小 (最大5MB)
    if len(img_data) > 5 * 1024 * 1024:
        raise Exception("图片大小超过5MB限制")

    # 3. Base64编码
    img_base64 = base64.b64encode(img_data).decode("utf-8")

    # 4. 调用OCR接口
    access_token = get_access_token()
    if not access_token:
        raise Exception("获取access_token失败")

    url = f"https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token={access_token}"
    payload = {
        'image': img_base64,
        'id_card_side': 'front',
        'detect_quality': 'true'  # 启用质量检测
    }
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}

    try:
        response = requests.post(url, headers=headers, data=urllib.parse.urlencode(payload))
        response.raise_for_status()
        print(f"OCR结果: {response.json()}")
        return response.json()
    except Exception as e:
        raise Exception(f"OCR接口调用失败: {str(e)}")


# ------------------------------
# 2. 作者注册接口 (仅负责入队)
# ------------------------------
@page_user.post("/register", summary="注册作者", tags=["用户"])
async def register_author(
        pen_name: str = Form(...),
        introduction: Optional[str] = Form(None),
        sample_work: Optional[str] = Form(None),
        id_card_front_file: UploadFile = File(...),
        id_card_back_file: Optional[UploadFile] = File(None),
        authorization: str | None = Header(None)):
    """接收作者注册信息，上传图片并将任务入队"""
    # 1. 验证Token
    if not authorization or not authorization.lower().startswith("bearer "):
        raise HTTPException(status_code=401, detail="缺少Bearer Token")
    token = authorization.split(" ", 1)[1].strip()
    user_id = get_current_user(token)
    if not user_id or not await User.exists(id=user_id):
        raise HTTPException(status_code=401, detail="无效用户")

    # 2. 检查重复申请
    if await AuthorVerification.exists(user_id=user_id):
        raise HTTPException(status_code=400, detail="已提交过认证申请")

    # 3. 上传身份证正面到七牛云
    allowed_ext = {'.jpg', '.jpeg', '.png'}
    front_ext = os.path.splitext(id_card_front_file.filename)[1].lower()
    if front_ext not in allowed_ext:
        raise HTTPException(status_code=400, detail="正面照片仅支持jpg/png")

    # 读取文件并上传
    front_filename = f"front_{user_id}_{int(time.time())}{front_ext}"
    try:
        file_data = await id_card_front_file.read()
        q = Auth(QINIU_ACCESS_KEY, QINIU_SECRET_KEY)
        token = q.upload_token(QINIU_BUCKET, front_filename, 3600)
        ret, info = put_data(token, front_filename, file_data)
        if info.status_code != 200:
            raise Exception("上传失败")
        front_url = f"{QINIU_DOMAIN}/{front_filename}"
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"正面照片上传失败: {str(e)}")

    # 4. 上传身份证反面（可选）
    back_url = None
    if id_card_back_file:
        back_ext = os.path.splitext(id_card_back_file.filename)[1].lower()
        if back_ext not in allowed_ext:
            raise HTTPException(status_code=400, detail="反面照片仅支持jpg/png")
        back_filename = f"back_{user_id}_{int(time.time())}{back_ext}"
        try:
            file_data = await id_card_back_file.read()
            token = q.upload_token(QINIU_BUCKET, back_filename, 3600)
            ret, info = put_data(token, back_filename, file_data)
            if info.status_code == 200:
                back_url = f"{QINIU_DOMAIN}/{back_filename}"
        except Exception as e:
            print(f"反面照片上传失败: {str(e)}")  # 不阻断主流程


    verification_data = {
        "user_id": user_id,
        "pen_name": pen_name,
        "introduction": introduction,
        "sample_work": sample_work,
        "id_card_front_url": front_url,
        "id_card_back_url": back_url,
        "status": AuthorVerificationStatus.PENDING,
        "real_name":None,
        "id_card":None
    }


    await redis_conn.lpush("id_card_verify_queue",json.dumps(verification_data))

    return {
        "code": 200,
        "message": "申请已提交，正在审核中",
        "data": {"verification_id":None}
    }




active_connections : List[WebSocket]  = []

client_connections:Dict[str,WebSocket] = {}


async def send_to_client(client_id: str, message: str):
    if client_id in client_connections:
        await client_connections[client_id].send_text(message)


@list_rz_wedSockert.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):

    await websocket.accept()

    active_connections.append(websocket)

    client_connections[client_id] = websocket

    print(f"客户端 {client_id} 已连接，当前连接数：{len(active_connections)}")



# ------------------------------
# 3. 定时任务（处理身份证验证）
# ------------------------------
async def process_verify_queue():
    """从Redis队列读取任务，执行OCR并更新状态"""
    try:

        await redis_conn.ping()  # 测试连接
    except Exception as e:
        print(f"Redis连接失败: {str(e)}")
        return

    while True:
        try:
            # 从队列取任务（阻塞10秒，无任务则退出循环）
            result = await redis_conn.brpop(["id_card_verify_queue"], timeout=10)
            if not result:
                break  # 无任务，等待下一次调度

            _, task_str = result
            task = json.loads(task_str)
            # verification_id = task["user_id"]
            user_id = task["user_id"]
            front_url = task["id_card_front_url"]

            # 获取验证记录
            verification = await AuthorVerification.get_or_none(
                user_id=user_id,
            )
            if verification:
                print(f"验证记录已存在: {user_id},")
                continue
                return {"code": 400, "message": "验证记录已存在", "data": None}

            # 执行OCR识别
            ocr_result = ocr_id_card(front_url)
            print(ocr_result)

            # 检查图片质量
            image_status = ocr_result.get("image_status", "")
            quality_errors = {
                "over_exposure": "曝光过度",
                "under_exposure": "曝光不足",
                "blurred": "图像模糊"
            }
            if image_status in quality_errors:
                raise Exception(f"照片质量问题: {quality_errors[image_status]}")
            if image_status not in ["normal", ""]:
                raise Exception(f"无效照片状态: {image_status}")

            print(ocr_result)
            # 提取姓名和身份证号
            words = ocr_result.get("words_result", {})
            real_name = words.get("姓名", {}).get("words", "").strip()
            id_card_num = words.get("公民身份号码", {}).get("words", "").strip()

            # 在创建 AuthorVerification 实例前添加验证
            if not real_name:
                raise Exception(detail="真实姓名不能为空")
            if not id_card_num or len(id_card_num) != 18:
                raise Exception("身份证号格式无效")

            verification = await AuthorVerification.create(
                user_id=user_id,
                pen_name=task["pen_name"],
                introduction=task["introduction"],
                sample_work=task["sample_work"],
                id_card_front_url=front_url,
                id_card_back_url=task["id_card_back_url"],
                status=AuthorVerificationStatus.APPROVED,
                real_name=real_name,
                id_card=id_card_num
            )
            user = await User.get_or_none(id=user_id)
            await user.update(role=2)
            await user.save()
            await verification.save()
            print(f"验证通过: 用户{user_id}, 姓名{real_name}")

            await send_to_client(client_id=user_id, message="验证成功")

        except Exception as e:
            # 验证失败，更新状态
            if 'verification' in locals() and verification:
                verification.status = AuthorVerificationStatus.REJECTED
                verification.reject_reason = str(e)  # 需要在模型中添加reason字段
                await verification.save()
            print(f"处理任务失败: {str(e)}")


def add_jobs():
    scheduler.add_job(
        func=process_verify_queue,
        trigger="interval",
        seconds=15,
        id="verify_queue_processor"
    )


@list_rz_wedSockert.onn_event("startup")
def startup_event():
    print("身份证验证开始")
    add_jobs()
    scheduler.start()


@list_rz_wedSockert.on_event("startup")
def shutdown_event():
    """应用关闭时，关闭调度器"""
    scheduler.shutdown()
    print("身份证验证结束")